package com.ionicframework.myapp619314;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.TranslateAnimation;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.FrameLayout;

import java.util.ArrayList;
import java.util.List;


/**
 * Copyright (C), 2008-2015, Huawei Tech. Co., Ltd.
 * <p/>
 * Description : 旋转式排列菜单,环形布局菜单,支持类似listView式的滑动
 *
 * @author [pWX273343] 2015年10月29日
 * @version V100R001
 * @since V100R001
 */
public class RotatoMenu extends FrameLayout {
    /** 从某角度到某角度排列 */
	// private float fromAngel = (float) Math.PI * 1.75f, toAngle = (float)
	// Math.PI * 0.75f;
	private float fromAngel = (float) Math.PI * 1.65f, toAngle = (float) Math.PI * 0.85f;
	/** 角度间隔 */
	private float angleInterval = 0;

	private BaseAdapter adapter;
	/** 从角度到角度排列的默认item个数 */
	private int numColume = 5;
	/** 中央按钮 */
	private Button centerButton = null;
	/** items */
	private List<View> childs = new ArrayList<View>();
	/** 记录item角度具体分布 */
	private List<Float> angles = new ArrayList<Float>();
	/** 开始位置 */
	private int firstVisiablePosition = 0;
	/** 环形半径 */
	private float mRange = -1;

	/** item大小 */
	private int mItemWidth = 0, mItemHeight = 0;
	private int mMenuSize = 0;
	/** 旋转中心 */
	private int mCenterX = -1, mCenterY = -1;
	/** 是否展开 */
	private boolean isShowing = false;

	private GestureDetector detector;

	private int lastVisiablePosition = 0;

	private float startAngle = 315, sweepAngle = 180;

	private boolean isDrawRing = true;

	public RotatoMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
		initAttribute(context, attrs);
		addCenterButton();
	}

	private void initAttribute(Context context, AttributeSet attrs) {
		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ringMenu);

		mMenuSize = a.getDimensionPixelSize(R.styleable.ringMenu_menuSize,
				(int) context.getResources().getDimension(R.dimen._40dp));
		fromAngel = a.getInt(R.styleable.ringMenu_fromAngle, 297);
		fromAngel = (float) (fromAngel / 180 * Math.PI);
		toAngle = a.getInt(R.styleable.ringMenu_toAngle, 153);
		toAngle = (float) (toAngle / 180 * Math.PI);

		startAngle = a.getInt(R.styleable.ringMenu_ringStartAngle, 315);
		sweepAngle = a.getInt(R.styleable.ringMenu_ringSweepAngle, 180);

		mItemWidth = a.getDimensionPixelSize(R.styleable.ringMenu_itemWidth, (int) getContext().getResources()
				.getDimension(R.dimen._30dp));
		mItemHeight = a.getDimensionPixelSize(R.styleable.ringMenu_itemHeight, (int) getContext().getResources()
				.getDimension(R.dimen._30dp));

		mRange = a.getDimensionPixelSize(R.styleable.ringMenu_range, -1);
		mCenterX = a.getDimensionPixelSize(R.styleable.ringMenu_centerX, -1);
		mCenterY = a.getDimensionPixelSize(R.styleable.ringMenu_centerY, -1);

		numColume = a.getInt(R.styleable.ringMenu_numColume, 5);

		isDrawRing = a.getBoolean(R.styleable.ringMenu_drawRing, true);
		Drawable drawable = a.getDrawable(R.styleable.ringMenu_centerButtonBackgroud);
		if (drawable != null) {
			centerButton = new Button(context);
			centerButton.setBackground(drawable);
		}
		a.recycle();
	}

	public RotatoMenu(Context context) {
		super(context);
		addCenterButton();
	}

	/**
	 * 
	 * @描述:此处添加函数描述信息
	 * 
	 * @作者 [pWX273343] 2015年10月28日
	 */
	private void initView() {
		if (mItemWidth == 0) {
			mItemWidth = (int) getContext().getResources().getDimension(R.dimen._30dp);
		}
		if (mItemHeight == 0) {
			mItemHeight = (int) getContext().getResources().getDimension(R.dimen._30dp);
		}
		if (mMenuSize == 0) {
			mMenuSize = (int) getContext().getResources().getDimension(R.dimen._40dp);
		}

		detector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
			private float lastAngle = 0;
			private float firstAngle = 0;

			private boolean mAcceptEvent = false;

			@Override
			public boolean onDown(MotionEvent e) {
				return mAcceptEvent = !isInCenter(e) && !isOutSideAngle(e);
			}

			/** 是否在转盘中心,转盘中心转起来太快,不接受事件.同样跨越转盘中心的操作也会导致转盘角度快速变更 */
			private boolean isInCenter(MotionEvent e) {
				// 点击的的距离
				float distance = (float) Math.sqrt((e.getY() - mCenterY) * (e.getY() - mCenterY)
						+ (e.getX() - mCenterX) * (e.getX() - mCenterX));
				return distance < mMenuSize * 0.707;
			}

			/** 计算角度是否在item分布的角度之外,角度分布之外,角度计算会引起意外,比如突然从360度变到0,需要复杂的判断 */
			private boolean isOutSideAngle(MotionEvent e) {
				float angle = getAngleFromEventPoint(e);
				if (fromAngel >= toAngle) {
					return angle > fromAngel || angle < toAngle;
				} else {
					return angle < fromAngel || angle > toAngle;
				}
			}

			/** 计算角度,该方法仅仅使用于2,3,4 */
			private float getAngleFromEventPoint(MotionEvent e) {
				float y = e.getY() - mCenterY;
				float x = e.getX() - mCenterX;
				float angle = (float) Math.atan2(y, x);
				if (angle < 0) {
					angle += Math.PI * 2;
				}
				return angle;
			}

			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
				if (e1 == null || e2 == null || !mAcceptEvent) {
					return false;
				}
				if (isInCenter(e2) || isOutSideAngle(e2)) {
					return false;
				}
				float angle0 = getAngleFromEventPoint(e1);
				if (firstAngle != angle0) {
					lastAngle = firstAngle = angle0;
				}
				float angleTo = getAngleFromEventPoint(e2);
				// 转换成移动角度
				float angleR = (angleTo - lastAngle);
				lastAngle = angleTo;
				for (int i = 0; i < angles.size(); i++) {
					float angle = angles.remove(i);
					angles.add(i, angle + angleR);
				}
				// 顺时针
				if (angleR > 0) {
					float lastAngle = angles.get(angles.size() - 1);
					float firstAngle = angles.get(0);
					// 最后一个view滑出,但超过边界
					if (lastVisiablePosition == adapter.getCount() - 1 && lastAngle > toAngle) {
						angles.clear();
						// 最后不能滑动
						for (int i = 0; i < childs.size(); i++) {
							// 从末尾逐条向前添加,从toAngle开始
							angles.add(0, toAngle - angleInterval * i);
						}
						applyChildsAngleToLocation();
						return false;
					}
					// 已经等于边界值,直接不在响应
					else if (lastVisiablePosition == adapter.getCount() - 1 && lastAngle == toAngle) {
						return false;
					}

					// 当最后一个View的角度,大于toAngle,即可以创建新的view时候
					if (lastAngle > toAngle + Math.PI / 6) {
						// 查看当前位置下面是否还有View
						if (lastVisiablePosition < adapter.getCount() - 1) {
							View child = adapter.getView(++lastVisiablePosition, null, null);
							childs.add(child);
							angles.add(lastAngle + angleInterval);

							LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
							addView(child, getChildCount() - 1, p);
						} else {
							return false;
						}
					}
					if (firstAngle > fromAngel - angleInterval) {
						// gaiView已经不可见,可以移除
						View child = childs.remove(0);
						angles.remove(0);
						removeView(child);
						// selection
						firstVisiablePosition++;
					}
				}
				// 逆时针旋转
				else {
					float lastAngle = angles.get(angles.size() - 1);
					float firstAngle = angles.get(0);
					// 第一个边界超过
					if (firstVisiablePosition == 0 && firstAngle < fromAngel) {
						angles.clear();
						// 最后不能滑动
						for (int i = 0; i < childs.size(); i++) {
							angles.add(angleInterval * i + fromAngel);
						}
						applyChildsAngleToLocation();
						return false;
					} else if (firstVisiablePosition == 0 && firstAngle == fromAngel) {
						return false;
					}

					if (firstAngle < fromAngel) {
						// 查看当前位置上面是否还有View
						if (firstVisiablePosition > 0) {
							View child = adapter.getView(firstVisiablePosition - 1, null, null);
							childs.add(0, child);
							angles.add(0, firstAngle - angleInterval);
							LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
							addView(child, getChildCount() - 1, p);
							firstVisiablePosition--;
						} else {
							// 不可继续滚动
							return false;
						}
					}
					if (lastAngle < toAngle + angleInterval) {
						// 最后一个View已经不可见,移除
						View child = childs.remove(childs.size() - 1);
						angles.remove(angles.size() - 1);
						removeView(child);
						lastVisiablePosition--;
					}

				}
				applyChildsAngleToLocation();
				return true;
			}
		});

		paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
		paint.setColor(0xffff00ff);
		paint.setStyle(Paint.Style.STROKE);
	}

	private void addCenterButton() {
		if (centerButton == null) {
			centerButton = new Button(getContext());
			centerButton.setBackgroundResource(android.R.drawable.btn_radio);
		}
		FrameLayout.LayoutParams p = new LayoutParams(mMenuSize, mMenuSize);
		addView(centerButton, p);

		centerButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// 弹出或收起菜单
				if (isShowing) {
					collapse();
				} else {
					expand();
				}
			}

		});
	}

	public BaseAdapter getAdapter() {
		return adapter;
	}

	public void setAdapter(BaseAdapter adapter) {
		this.adapter = adapter;
		initView();
		// 清除原来的view
		if (childs != null || !childs.isEmpty()) {
			for (int i = 0; i < childs.size(); i++) {
				View view = childs.get(i);
				removeView(view);
				childs.remove(view);
			}
			angles.clear();
		}
		// 上层View个数,中央button为一个
		if (numColume <= adapter.getCount()) {
			// 计算平均分布的角度
			angleInterval = (toAngle - fromAngel) / (numColume - 1);
			// 从起始位置,取numcolume个视图
			for (int i = firstVisiablePosition; i < adapter.getCount() && i < firstVisiablePosition + numColume; i++) {

				View child = adapter.getView(i, null, null);
				child.setVisibility(isShowing ? View.VISIBLE : View.INVISIBLE);
				childs.add(child);
				LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
				addView(child, getChildCount() - 1, p);

				// 排列的角度

				float angle = angleInterval * i + fromAngel;
				angles.add(angle);
				lastVisiablePosition = i;

			}
		} else {
			angleInterval = (toAngle - fromAngel) / adapter.getCount();
			for (int i = 0; i < adapter.getCount(); i++) {

				View child = adapter.getView(i, null, null);
				child.setVisibility(isShowing ? View.VISIBLE : View.INVISIBLE);
				childs.add(child);
				LayoutParams p = new LayoutParams(mItemWidth, mItemHeight);
				addView(child, getChildCount() - 1, p);
				// 排列的角度
				float angle = angleInterval + fromAngel;
				angles.add(angle);
			}
			lastVisiablePosition = adapter.getCount() - 1;
		}
		// refreshChilds();
	}

	private boolean firstMeasure = true;

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int width = MeasureSpec.getSize(widthMeasureSpec);
		if (firstMeasure) {
			firstMeasure = false;
			if (mRange < 0) {
				mRange = width / 2 - mItemWidth / 2 - getPaddingLeft();
			}
			if (mCenterX < 0 || mCenterY < 0) {
				mCenterX = width / 2;
				mCenterY = width / 2;
			}
			applyChildsAngleToLocation();
		}
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		if (centerButton != null)
			// 布局中按钮的位置
			centerButton.layout(mCenterX - mMenuSize / 2, mCenterY - mMenuSize / 2, mCenterX + mMenuSize / 2, mCenterY
					+ mMenuSize / 2);
	}

	public int getNumColume() {
		return numColume;
	}

	/**
	 * 
	 * @描述:分布的个数
	 * 
	 * @param numColume
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setNumColume(int numColume) {
		this.numColume = numColume;
	}

	public Button getCenterButton() {
		return centerButton;
	}

	/**
	 * 
	 * @描述:设置用来弹出菜单的按钮
	 * 
	 * @param centerButton
	 * @param menuSize
	 *            按钮的宽高
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setCenterButton(Button centerButton, int menuSize) {
		if (this.centerButton != null) {
			removeView(this.centerButton);
		}
		this.centerButton = centerButton;
		this.mMenuSize = menuSize;
		addCenterButton();
	}

	/**
	 * 
	 * @描述:收起菜单
	 * 
	 * @作者 [pWX273343] 2015年10月28日
	 */
	public void collapse() {
		isShowing = false;
		for (int i = 0; i < childs.size(); i++) {
			View view = childs.get(i);
			view.setVisibility(View.INVISIBLE);
			TranslateAnimation translate = new TranslateAnimation(0, mCenterX - mItemWidth / 2f - view.getX(), 0,
					mCenterY - mItemHeight / 2f - view.getY());
			translate.setDuration(250 + i * 50);
			translate.setStartOffset(i * 50);

			view.startAnimation(translate);
		}
	}

	/**
	 * 
	 * @描述:展开菜单
	 * 
	 * @作者 [pWX273343] 2015年10月28日
	 */
	public void expand() {
		isShowing = true;
		for (int i = 0; i < childs.size(); i++) {
			final View view = childs.get(i);
			view.setVisibility(View.VISIBLE);
			// 移动动画
			TranslateAnimation translate = new TranslateAnimation(mCenterX - mItemWidth / 2f - view.getX(), 0, mCenterY
					- mItemHeight / 2f - view.getY(), 0);

			translate.setDuration(250 + i * 50);
			translate.setStartOffset(i * 50);

			view.clearAnimation();
			view.startAnimation(translate);

		}
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent e) {
		if (isShowing) {

			detector.onTouchEvent(e);
		}
		super.dispatchTouchEvent(e);
		return true;
	}

	/**
	 * 
	 * @描述:设置item分布的角度,如从270到180,角度以x轴方向顺时针旋转,来计算,那么从270到180就是从上往左分配
	 * 
	 * @param fromAngel
	 * 
	 * @param toAngle
	 * 
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setRotatoAngle(float fromAngel, float toAngle) {
		this.fromAngel = (float) (fromAngel / 180 * Math.PI);
		this.toAngle = (float) (toAngle / 180 * Math.PI);
	}

	public float getRange() {
		return mRange;
	}

	/**
	 * 
	 * @描述:设置旋转半径
	 * 
	 * @param range
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setRange(float range) {
		this.mRange = range;
	}

	/**
	 * 
	 * @描述:菜单项大小
	 * 
	 * @return
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public int[] getItemSize() {
		return new int[] { mItemWidth, mItemHeight };
	}

	/**
	 * 
	 * @描述:设置各个菜单的大小,即宽高
	 * 
	 * @param itemSize
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setItemSize(int itemWidth, int itemHeight) {
		this.mItemWidth = itemWidth;
		this.mItemHeight = itemHeight;
	}

	/**
	 * 
	 * @描述:设置旋转的中心轴
	 * 
	 * @param centerX
	 * @param centerY
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setRotatoCenter(int centerX, int centerY) {
		this.mCenterX = centerX;
		this.mCenterY = centerY;
	}

	public int getCenterY() {
		return mCenterY;
	}

	/**
	 * 
	 * @描述:是否需要绘制用来遮挡的圆环
	 * 
	 * @param draw
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setDrawRing(boolean draw) {
		isDrawRing = draw;
	}

	/**
	 * 
	 * @描述:设置绘制遮盖圆环
	 * 
	 * @param startAngle
	 *            从某个角度开始,如45
	 * @param sweepAngle
	 *            绘制环形跨越的角度,如180
	 * @param color
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setDrawRingAngle(float startAngle, float sweepAngle, int color) {
		this.startAngle = startAngle;
		this.sweepAngle = sweepAngle;
		isDrawRing = true;
	}

	/**
	 * 
	 * @描述:设置从第几个item开始
	 * 
	 * @param selection
	 * @作者 [pWX273343] 2015年10月29日
	 */
	public void setSelection(int selection) {
		firstVisiablePosition = selection;
	}

	/**
	 * 
	 * @描述:讲角度分布转换成位置,并调整child位置
	 * 
	 * @作者 [pWX273343] 2015年10月30日
	 */
	private void applyChildsAngleToLocation() {
		for (int i = 0; i < childs.size(); i++) {
			View child = childs.get(i);
			float angle = angles.get(i);
			// 计算item中心位置
			float centerX = mCenterX + (float) Math.cos(angle) * mRange;
			float centerY = mCenterY + (float) Math.sin(angle) * mRange;

			// 设置item位置
			child.setX(centerX - mItemWidth / 2);
			child.setY(centerY - mItemHeight / 2);
		}
	}

	// 擦除画笔
	private Paint paint;

	@Override
	protected void dispatchDraw(Canvas canvas) {
		if (isDrawRing) {
			canvas.drawColor(0x00ffffff);
			int saveCount = canvas.saveLayer(new RectF(canvas.getClipBounds()), null, Canvas.ALL_SAVE_FLAG);
			super.dispatchDraw(canvas);

			RectF rect = new RectF(mItemWidth / 2, mItemWidth / 2, canvas.getWidth() - mItemWidth / 2,
					canvas.getHeight() - mItemWidth / 2);
			if (rect != null) {
				paint.setStrokeWidth(mRange - mItemWidth / 2);
				canvas.drawArc(rect, startAngle, sweepAngle, false, paint);
			}
			canvas.restoreToCount(saveCount);
		} else {
			super.dispatchDraw(canvas);
		}
	}
}
